5 ms·
I liked the article, but there's something I need to point out regarding CSS preprocessors. It's way more important than making CSS "a bit better". Preprocesso
by paulojreis 11y ago
I liked the article, but there's something I need to point out regarding CSS preprocessors. It's way more important than making CSS "a bit better".
Preprocessors allow you to achieve modularity and DRYness. They allow you to move the object-composition duty from the browser to the build process - hence avoiding overloading the browser with composition (i.e. composing a class with SASS mixins or extends, instead of plugging many classes in a single HTML element). They allow you to easily express relationship through class names instead of relying on DOM hierarchy (separation of concerns). And, obviously, they allow variables! Common and centralized palettes, sizing definitions, typography definitions; also, "computable" definitions (e.g. deriving a shades/tints palettes via the built-in color management functions, or computing a typography scale from a base size).
If you have the time to learn CSS and a preprocessor adequately (and think about how to tackle common architectural issues having these characteristics in mind, isntead of borrowing solutions from e.g. OOP), then you might have clean, elegant and maintainable CSS (instead of a hairy jungle of rules that nobody in your team would want to mess with).
- intruder 11y agoDo you have a resource for the last point you mentioned?
- paulojreis 11y agoNot exactly, it's something I've been noticing from my experience with CSS and many teams with many members which were experienced programmers but without any CSS experience. I've shared these ones with my team, however: http://philipwalton.com/articles/css-architecture/ http://philipwalton.com/articles/css-architecture/ http://philipwalton.com/articles/side-effects-in-css/ http://philipwalton.com/articles/side-effects-in-css/ http://philipwalton.com/articles/extending-styles/ http://philipwalton.com/articles/extending-styles/ http://benfrain.com/the-ten-commandments-of-sane-style-sheets/ http://benfrain.com/the-ten-commandments-of-sane-style-sheet... P.S. A good heuristic I'd like to point out (and hard-code in any CSS newbie's brain) is that if you're relying on DOM structure (e.g. styling X if he is a descendant or sibling of Y), then you're doing it wrong. Very, very few exceptions to this. Structure (HTML) is a different concern than styling (CSS) and it might change frequently; it should have minimal impact on styling. P.P.S. Another good notion is that CSS is truly like Tetris. Errors do pile up. If you are over-specific when defining a selector, soon you'll have to do a even-more-specific one to override it. If you are too confident and define a leaky rule (e.g. all `<p>` elements inside a given widget), soon you'll have to create code to override it.
- gotchange 11y agois that if you're relying on DOM structure (e.g. styling X if he is a descendant or sibling of Y), then you're doing it wrong. Actually this is the way to do it without going overboard with it. Even UI frameworks like Boostrap or Foundation rely on this convention to style elements on the page. Littering the HTML markup with classes all over the place for the illusion of "loose coupling" between the CSS and HTML is an anti-pattern and counter-productive. You just need to use classes when appropriate and necessary and then rely on the inherent and predictable relations between HTML elements to supply styling information and close the deal.
- paulojreis 11y agoI don't like the Bootstrap approach very much. I'd rather litter the markup with classes and then be able to change their order and location in the DOM without affecting styles than having to do changes both in HTML in CSS files - bear in mind that, with DOM dependency, most style changes would imply you to change or at least check the HTML file. It will also make you end up "plugging" exceptions on top of exceptions - element X looks like A when he's a child of Y, but then it will have to look like B when he's a descendant of Z (something common with a page-level class, for instance). This is way safer and maintainable with BEM-like modifiers. I'd say that waiting for "inherent and predictable relations between DOM elements" is a disaster waiting to happen. Of course, there are exceptions (the table mark-up and table styles might be coupled, I guess), but you should try to avoid it. Take a look at http://philipwalton.com/articles/side-effects-in-css/ http://philipwalton.com/articles/side-effects-in-css/, he has a few good points.
- nmjohn 11y agoIf you're looking to improve the CSS you end up writing - I highly suggest considering BEM [0]. It stands for block, element, modifier and defines a fairly rigid structure to build components with. tl;dr: It promotes extremely simple, component based/modular css that is _trivial_ to refactor with confidence unexpected regressions won't pop up. I'm primarily a backend engineer, but I do full-stack work, especially in my free time, and after seeing it used by our front-end devs at work I decided to try it on my own project - and for the first time ever, I felt like the CSS I was writing actually made logical sense in the same way any program I'd write makes logical sense. Adding constraints is majorly helpful when your language has hundreds of virtually equivalent ways (or at least seemingly equivalent) of doing the same thing - it's just setting yourself up for confusion later. With or without any sort of preprocessor, BEM is still crazy beneficial if you have a codebase with many people touching the styles, it - a.) promotes good css practices by limiting the usage of entirely un-necessary slow css selectors because they'd require convention to be broken (and then caught easily in a code review) b.) promotes extremely DRY components c.) defines a very simple yet specific way of handling style variations that make DRY component variants (eg a button component could have a red, green or blue modifier) obvious to everyone on the team in a way almost analogous to a primitive in a programming language -- most codebases don't otherwise have a defined pattern for this leading a lot of wheel reinvention and extra complexity which in turns breeds more complexity, leading to truly disgusting css. Of course there are downsides, by putting limits on a language some things will necessarily become more difficult/complex to accomplish, but I personally find the benefits far outweigh this. Additionally, I'm not sure how it works trying to integrate it into a mature codebase - I could see that being a challenge for some projects/CSS code styles, but I've not done that so can't speak from more than speculation. [0]: https://css-tricks.com/bem-101/ https://css-tricks.com/bem-101/
- dustingetz 11y agoI hear what you are saying about clean and elegant css being possible with preprocessors that add abstraction capabilities. I have never ever seen it in practice, at least nothing on par with the abstraction abilities of code. Can you post a medium scale example of clean & maintainable css that we might study?
- ceejayoz 11y agohttps://github.com/twbs/bootstrap/tree/master/less https://github.com/twbs/bootstrap/tree/master/less
- paulojreis 11y agoBootstrap is quite the opposite of what I'd consider good CSS architecture (although it's obviously a great project). Way too much reliance on DOM structure.
- DougWebb 11y agoOn a larger scale (overall layout of a page) CSS reliance on DOM structure is a bad thing. But on a small scale (layout of a component) the cleanest markup is usually going to require coordination between the CSS and the DOM structure (and JS if the component has custom behaviors.) This is true for basic html too. You could create a bullet list by adding a div with a class for the container and arbitrarily located divs with classes indicating that they're list items related to the container, and then use complicated CSS to pull it all together into a visual representation of a bullet list. Or, you could use a ul element for the container with direct child li elements for the items. Your visual style relies on the DOM structure, but overall it's a cleaner solution.
- paulojreis 11y agoWhy would you create a list with <div> elements? I understand your point; DOM structure has styling defaults and you have to play with it - 100% decoupling it's not possible. Still, trying to achieve decoupling between structure and styles doesn't mean that you should create bad mark-up. In your scenario, I'd use a list element (<ul> or <ol>, according to the nature of the data) with a class (e.g. .my-list) and list item elements also with a class if needed (<li> with e.g. .my-list__item). No complications here. If somewhere along the way someone wanted to to a navigation area with exactly the same styles but with a different mark-up (anchors inside a <nav>), you could reuse or extend those classes to a <nav> element for the container and <a> elements for items. That's another "level" of DOM independence.
- mr_mig 11y agoThis is a very deep insight on CSS preprocessor topic. I have used the phrase "a bit better" intentionally, so that I do not dive deep into it. Would you be so kind to give some comments on this thing: https://github.com/brainly/style-guide https://github.com/brainly/style-guide ?
- paulojreis 11y agoI can tell we're aligned regarding CSS architecture - and also regarding Angular. :) The style guide you linked is very clear and concise in explaining why BEM is great without being a panacea - it's ugly, but it's simple, predictable and solves many of the issues which arise with CSS nature (e.g. everything in CSS is global). I also liked the emphasis on having BEM as a naming convention, no more. Regarding how you introduce BEM, I would only: * Reinforce the idea that a BEM compliant worflow would typically allow developers to change mark-up without having to look up stylesheets and vice-versa; * Reinforce how much it would typically reduce side-effects! I'd also give a few words on the topic of using the preprocessor (mixins, extends and, obviously, variables) to achieve DRYness. * My argument to my team was to have readable semantic and obvious classnames (without style references in the name, e.g. no .blue-widget) which are "composed" via SASS (and SASS constructs might have style references in the name e.g. my-button @extends %blue-button); * The other argument, and the one I actually believe `philosophically is that this allows you transfer the object-composition duty from the browser to the build process. It just makes sense to me: why have thousands of clients composing styles (e.g. button class="btn btn-lg btn-primary") when this is predictable ahead-of-time (button class="my-btn", where .my-btn = @make-btn(lg, primary)). This gives you performance and, as I said above, the possibility to have readable class names - I don't exactly know what "btn btn-lg btn-primary" might be, but "btn-login" is quite obvious. In your contributing guidelines I noticed you have @extends with classes (e.g. @extend .mint-list). I use placeholders instead of classes to avoid side effects which are difficult to predict (even more so when you have a team with different levels of expertise). Here's why: http://csswizardry.com/2014/01/extending-silent-classes-in-sass/ http://csswizardry.com/2014/01/extending-silent-classes-in-s.... I'd also reinforce the notion - as less experienced developers do this quite often - of the different concerns of HTML (structure) and CSS (style). Newcomers to HTML seem to believe that HTML is a GUI mark-up language and, ergo, it shouldn't be problematic to use it as a presentational layer. As a practical example, "newcomers" usually have HTML elements only for presentational purposes, such as <div class="shadow"> or a list item used as a divider between other list items. I usually spend a few minutes of my time explaining how to avoid this using e.g. :before and/or :after.