16 ms·
CSS Modules
- danieltillett 11y agoHow does a post get to number 1 here with only 5 up votes?
- foxpc 11y agoIt's probably some sort of score decay over time. Surely, it the post was posted a couple of hours ago, 5 up votes would not cut it.
- josephmx 11y agoThere's extra weight to comments and how fast the upvotes are. If all votes are instant it'll go higher than votes over a longer period.
- danieltillett 11y agoThis is not great. I know there are controls in place to stop chain voting, but if it only takes 5 votes in 5 minutes to reach number 1 then the system is wide open to abuse.
- rgbrgb 11y agoMost systems are vulnerable if you poke around a bit. In my experience the HN voting ring detector is pretty wily.
- danieltillett 11y agoThat I agree with :) The problem is that no system can detect signal in five votes. The numbers are just too small to be significant.
- andrewingram 11y agoI've been using CSS Modules in a couple of projects (combined with PostCSS), am pretty happy so far. I think you could actually go one step further and embed the stylesheet in the React component's module using a tagged template string, I haven't looked into how you'd get webpack to extract this into CSS files, but I'm sure it's possible. Eg: https://gist.github.com/AndrewIngram/e3af5e8b70fd89a9a0d3 https://gist.github.com/AndrewIngram/e3af5e8b70fd89a9a0d3
- xzyfer 11y agoI've thought about this also. Alternatively some mixed format file like yaml front matter style.
- andreypopp 11y agoThat (extraction) can be done (React Style does that) but for it to be consistent with JS semantics you need to evaluate code at build time because such template strings can contain interpolations from JS world.
- andrewingram 11y agoAh yes, forget about the interpolation issue. I knew there was a reason I stopped digging into it
- sepokroce 11y agoSurely not the future.
- rdsubhas 11y agoNot sure why you're getting downvoted. Problems with CSS at Scale are very real (as mentioned in the slide). But this is a super complicated solution. Its like one of the head-over-heels approaches in JoelOnSoftware blogs. Surely there has to be a simpler way. Its good that the authors are trying. But just look at the picture on this article captioned "This is how intensely we’ve been thinking about CSS". That's where the whole complexity comes from I guess. Good solutions present themselves and fit naturally.
- kaoD 11y ago> Not sure why you're getting downvoted. Because it doesn't contribute anything but nonconstructive criticism. > Good solutions present themselves and fit naturally. Complex problems require complex solutions. Also, what's so complex and non-fitting about this solution? Explaining that (and your alternative solution) would be much better than simply criticizing as you and GP did. > Surely there has to be a simpler way. There's a technically simpler way: modules being part of the CSS spec. But they're not, so even if technically simpler as a solution, it's a political nightmare on which we developers have no control whatsoever. Driving forward the status quo with hacks (like to-JS transpilers did) is nothing but beneficial. Hacks drive standards. > "This is how intensely we’ve been thinking about CSS". That's where the whole complexity comes from I guess. How much have you been been thinking about CSS and fighting its flaws? Obviously not a lot.
- sepokroce 11y ago> Because it doesn't contribute anything but nonconstructive criticism. No, it's just an opinion and a comment on the sensationalistic article (sub)title.
- rimantas 11y agoThere is a simpler way. Even for large projects there is no need for the amount of CSS they usually have. It just takes some discipline and planning, alas that's often replaced by abdominations like BEM.
- IlPeach 11y agoAren't methodologies like SMACSS addressing such problems? I found interesting how the whole thing is specifically related to someone reading the CSS and not used to SASS.
- IlPeach 11y agoForget the last sentence, was referring to another link.
- fuzionmonkey 11y agoOne thing worth mentioning about class composition with CSS Modules is it allows for the convenient ergonomics of Sass's @extend without any of its problems. Sass @extend is actually counterproductive in terms of reducing filesize [1] and results in unwieldy, unreadable CSS rules [2]. In contrast, CSS Modules achieves true class reusability and optimal de-duplication of styles in a manner impossible with Sass, resulting in a nice Chrome Inspector view because the original classes are preserved and their composition is naturally represented. [1] https://tech.bellycard.com/blog/sass-mixins-vs-extends-the-data/ https://tech.bellycard.com/blog/sass-mixins-vs-extends-the-d... [2] http://pressupinc.com/blog/2014/11/dont-overextend-yourself-in-sass/ http://pressupinc.com/blog/2014/11/dont-overextend-yourself-...
- ploxiln 11y agoSo... CSS has the same global namespace issue as C, and this CSS Modules is the same solution as C++ namespaces and classes. They call it "mangling". https://en.wikipedia.org/wiki/Name_mangling#Name_mangling_in_C.2B.2B https://en.wikipedia.org/wiki/Name_mangling#Name_mangling_in... (further commentary prudently withheld)
- sbensu 11y agoI agree that mangling isn't ideal but the naming resolution rules are already defined in every browser and they use a global namespace! From a distance, I don't see a better approach to providing namespace-like-things.
- saidajigumi 11y agoBut just as with C++, that's effectively an implementation detail, and irrelevant to the larger issues addressed. BEM itself is just name-mangling structured for humans to execute manually. (wait, WAT.) We're talking about the cognitive model and load that designers and developers have to deal with when authoring styles. I see CSS Modules (and Radium and ...) as being a space for experiments that I hope will ultimately point the way to better "baked in" solutions. Similar to how ideas from Coffeescript were "merged back upstream" into ES6/ES7.
- andreypopp 11y agoAlso see styling[0] which is a loader for webpack which allows to generate CSS modules with JS. Files configured to use with this loader (usually `.style.js`) are executed at build time and produce CSS modules. You can use any JS abstractions for that (functions, modules, variables, ...) and any npm package available (color manipulation, typography, ...): import styling from 'styling' import {smallText} from './typography' import {colors} from './theme' export let caption = styling({ ...smallText, color: colors.text }) [0]: https://github.com/andreypopp/styling https://github.com/andreypopp/styling
- ekosz 11y agoThis is a very cool library. Thanks for the link. Have you used this in any projects yet?
- andreypopp 11y agoWe started to migrate away from pure CSS Modules to Styling in our apps. Code didn't hit production yet but we are close. Writing styles in JS instead of CSS gave us a huge expressiveness boost and allowed to use existing JS tooling such as eslint. At the same time all CSS tooling still can be applied to compilation result (such as autoprefixer). Also would be fun to write styles in TypeScript — statically typed styles sounds great.
- deleted 11y ago[deleted]
- serapath 11y agoHey, that looks great :-) I'll try it. What do you think of https://github.com/css-modules/css-modules/issues/23#issuecomment-132747421 https://github.com/css-modules/css-modules/issues/23#issueco...
- AlexeyMK 11y agoI was first introduce to the 'CSS as code' concept by Blake at https://github.com/blakeembrey/react-free-style https://github.com/blakeembrey/react-free-style - worth taking a look if you're considering using one of these tools.
- spankalee 11y agoShadow DOM completely solves this problem in a better way by scoping styles to a shadow root. The scoping allows the browser to be smarter about style recalc as well. I do really like the idea of importing CSS into JS as a module to access the classnames and IDs though. I would like to do a similar thing with HTML imports as modules: import references to elements based on id.
- ivanca 11y agoUnfortunately Shadow DOM inherits CSS properties such as color;font-family.
- TeeWEE 11y agoWhere do you read that? I just checked the spec and coundt find this exception to the rule.
- ivanca 11y agoI didn't, it is how it works in latest Chrome. In all fairness, that's how a blank browser works by default (e.g. Times News Roman is the inherited font-family if you don't specify one) so is very likely the intended behavior.
- spankalee 11y agoYes, certain properties cascade through the shadow boundary. That's completely intended, and easy to work around by using a shadow-scoped reset if you need to, but otherwise it's useful to be able to set the font or color for an entire tree-scope at once.
- TeeWEE 11y agoIndeed, i just posted the some comment, but you where first. The shadow dom solves the css modularity problem. And also comes with better "componetization of the web". React is imho not the end solution, and the virtual-dom and the diffing of nodes should actually be built into browsers, and not into a javascript framework...
- troels 11y agoAbstractions are fine and dandy until they break down and you have to pry them open. What I don't understand here, is why the generated code doesn't follow the already established BEM conventions which the posts explores initially.
- pauly 11y agoI'm with you, that generated css doesn't look right, something that generated the css BEM style makes more sense.
- egze 11y agoThe advantage of BEM naming is that it takes 0 effort to find your style definitions in code. .Button--disabled copied in the browser, will find exactly 1 definition in the project. .components_submit_button__normal__abc5436 will not find you anything.
- dantillberg 11y agoBut on the flipside, in the latter case, you don't even need to grep for it -- "components_submit_button__normal__abc5436" reads as "components_{filename}_{classname}...", so you know right away to go look in "submit_button.(css|less|etc)" for ".normal {...".
- egze 11y agoThis is certainly a less convenient approach. You always need to parse the class name in your head to open the correct file.
- lojack 11y agoAs a counter argument, when grepping files you still need to parse the output in order to open the correct file. And, yes I understand that you can have grep output a path name and pass that directly in as an argument to your text editor. Similarly, it'd be relatively trivial to write a bash function that'd parse the class name and find the correct file to open. Something like: function lookupcss() { find . | grep $(expr "$1" : '\(.*\)__.*' | sed 's/_/.*/g')".*\.css$"; }
- arxpoetica 11y agoTHIS. Living in a world of abnormally gross class names like `components_submit_button__normal__abc5436` sounds downright painful, UGH.
- dfunckt 11y agoRight, but what about the name? This isn't Cascading Style Sheets any more. Hmm let's see, Composable Style Sheets. There. Oh, wait...
- aleem 11y agoIt's wonderful that CSS problems have been distilled so clearly, it's been a long time coming. Radium[1] is really worth checking out, it's simple and clear. From the article: /* BEM */ .normal { /* all styles for Normal */ } .button--disabled { /* overrides for Disabled */ } .button--error { /* overrides for Error */ } .button--in-progress { /* overrides for In Progress */ /* CSS MODULES */ .normal { /* all styles for Normal */ } .disabled { /* all styles for Disabled */ } .error { /* all styles for Error */ } .inProgress { /* all styles for In Progress */ > In CSS Modules each class should have all the styles needed for that variant This seems like trading one set of problems for another. It violates DRY and consequently impacts code maintainability. The corollary is that .disabled should @include .normal and then define the overrides so you only have to define the base styles once in .normal... but that also requires discipline and code wrangling. > [BEM] requires an awful lot of cognitive effort around naming discipline. But the proposed alternative is not too different either: /* components/submit-button.css */ .error { ... } .inProgress { ... } This example just replaces BEM naming and namespacing with file naming and directory structure. [1]: https://github.com/FormidableLabs/radium https://github.com/FormidableLabs/radium EDIT: On second reading, the stuff in there is definitely not "Welcome to the future" exploring the "adjacent possible" realm--those are quite grandoise pretexts to a solution that is just as unwieldy.
- andrewingram 11y agoExcept as far as I can tell, with Radium you get zero support for pseudo classes and media queries until after the client-side JavaScript has downloaded and been initialised. This is acceptable if it's purely a client-side app, but if you're using an kind of server-side rendering it's clearly not good enough. I really don't want a lack of hover or focus effects on initial page load, and I really don't want my entire page layout to change once the JavaScript-powered media queries kick in.
- aleem 11y agoRadium is simple, for that I like it. Complexity comes with a price and there may be alternatives but Radium leverages JS expressions which I like. Quoting from the article again: /* components/submit-button.jsx */ import { Component } from 'react'; import styles from './submit-button.css'; export default class SubmitButton extends Component { render() { let className, text = "Submit" if (this.props.store.submissionInProgress) { className = styles.inProgress text = "Processing..." } else if (this.props.store.errorOccurred) { className = styles.error } else if (!this.props.form.valid) { className = styles.disabled } else { className = styles.normal } return <button className={className}>{text}</button> } } That looks unwieldy -- 4 if/else clauses just to deal with CSS. Contrast that with the example in "Usage" over at the Radium page https://github.com/FormidableLabs/radium https://github.com/FormidableLabs/radium -- much simpler.
- aldanor 11y agoHasn't this been already done in webpack (css-loader with local scope)? https://github.com/webpack/css-loader#local-scope https://github.com/webpack/css-loader#local-scope
- andreypopp 11y agoWebpack's css-loader implements CSS modules specificaton, see https://github.com/webpack/css-loader#css-modules https://github.com/webpack/css-loader#css-modules
- deleted 11y ago[deleted]
- yari_ashi_zero 11y agoHTML is for hypertext documents, and CSS an organ of the same organism called 'HTML/CSS'. It's made for text documents, and applying it to the implementation of GUI-centric applications has always been an ugly hack. For awhile (90s to 00s AJAX) it was necessary, and now the whole professional ecosystem has built up tremendous inertia over the millions of accumulated people/hours of perfecting this 'competency'/hack. Now though, I would recommend to switch over to building 2D webapps entirely out of SVGs (say with React + Flux) e.g.: https://github.com/Terebinth/Vickers https://github.com/Terebinth/Vickers or, even better, to building them entirely out of WebGL. SVGs are easy and would lead to a wonderfully efficient workflow, but I think WebGL holds the advantage for performance considerations, given the way it goes to the hardware.
- wereHamster 11y agoI don't believe WebGL is suitable for rendering applications. Look at game UIs, they usually are either crap (low-cost games, where devs didn't sped too much time and simply blit button sprites somewhere on screen), or the authors had to implement a widget set on top of GL (WoW comes to mind). But a widget set is exactly what React and web components give you (built in top of basic building blocks like divs and spans and of course CSS for styling). And while HTML was initially created for hypertext documents, it doesn't mean it can't be used for somthing else. I disagree that it's an ugly hack. Some parts may not be suitable for GUI apps (uhm, like <blink>), but then simply don't use them in your application. Or implement something better on top of the good parts (like React did). Eventually the good parts may be come standard.
- Davertron 11y agoMoving entirely to svg for user interface has some of its own issues (i.e. there's no default layout engine in svg; everything is essentially absolutely positioned...) but would be interesting to think about. Moving entirely to WebGL would only be viable if you don't care at all about accessibility though. For some subset of applications that might be acceptable (i.e. games), but for something like gmail or other similar applications it's definitely not.
- 11y ago
- Kequc 11y agoIt feels to me that this conversation is quite old I'm finding myself not convinced by the examples put forward in the article. It looks like a lot of unnecessary complexity. You can have a lot of success by simply picking a common css convention. .mybutton /* all styles for Normal */ .mybutton.disabled /* overrides for Disabled */ .mybutton.error /* overrides for Error */ .mybutton.in-progress /* overrides for In Progress */ This is simpler and works incredibly well with javascript because I don't have to find replace remove a subset. I just addClass('disabled') removeClass('disabled').
- prezjordan 11y agoNow what if you wanted to bring in another button - a very similar one - with slightly different styles?
- Kequc 11y agoYou extend the styles now you perhaps have: .mybutton /* all styles for Normal */ .mybutton.skewed /* overrides for Skewed */ .mybutton.disabled /* overrides for Disabled */ class="mybutton skewed disabled" The suggestion in the OP would be that each one of those classes contain all of the styles for the button. That isn't necessary. Plus it requires, what I count, a minimum of two additional language abstractions in order to do it.
- talmand 11y agoExcellent answer. I love these "gotcha" examples when taking something that should be relatively simple and trying to make it more complicated to prove, um, something. I wish people would realize that making their CSS more complicated and bloated is not necessarily the answer.
- NathanCH 11y agoI agree, a lot of these solutions come from bad CSS. Not because CSS is bad.
- lo_fye 11y ago"The composes keyword says that .normal includes all the styles from .common" -- great, except you have the meaning of the word reversed. In the context above it actually means ".normal is part of .common", which is clearly not the intent. If you wanted it to mean that ".normal includes all the styles from .common" then .normal should be "composedOf: common"
- martin-adams 11y agoCorrect. Would the word 'comprises' be more appropriate?
- lo_fye 11y agoOh, yes, I like that much more :) I've created this as an issue on their github repo, at https://github.com/css-modules/css-modules/issues/24 https://github.com/css-modules/css-modules/issues/24
- bobwaycott 11y agoI stumbled upon the Github issue and then found the HN reference. I commented with some additional thoughts and keyword options. I don't think 'comprises' would be the best choice here; it has quite a stricter meaning than 'includes' and its synonyms.
- martin-adams 11y agoWhat about 'inherits' or 'extends' to match known programming terms?
- acjohnson55 11y agoReminds me of the one-man Wikipedia crusade against this misusage: http://www.npr.org/2015/03/12/392568604/dont-you-dare-use-comprised-of-on-wikipedia-one-editor-will-take-it-out http://www.npr.org/2015/03/12/392568604/dont-you-dare-use-co...
- chinchang 11y agoThis seems like too much abstraction (magic) of things. Plus those auto generated classes really look odd and would make debugging difficult.
- mradmin 11y agoI assume soucemaps would solve this.
- sic1 11y agoIt's lovely to assume this, but I see no mention of sourcemaps anywhere. This was my immediate gripe, debugging. Yea, the class name should point you to the file you want to look at, but that is still manual legwork. And the whole atomic css-like pitch he has with the over-the-top `composes` functionality looks like its own nightmare. I'll watch from over here and see if this pans out for ya'll.
- mradmin 11y agoI can't speak from experience with regards to this particular approach, but I've worked with css-modules with webpack (css-loader), and debugging the class names is no problem at all, CSS source-maps point to the source, you can view the source code within your developer tools. It shouldn't really be any different than debugging Sass generated CSS, for example.
- patrikh 11y agoWebpack allows you to change the format through its loader configuration. Perhaps, this could get implemented to CSS Modules too, if it’s not already. loaders: [ ... { test: /\.css$/, loader: 'css?localIdentName=[name]__[local]___[hash:base64:5]' } ]
- pearjuice 11y agoAm I the only one who scrolled up and down a few times just to verify the background was changing its color and it wasn't a bug in f.lux which kicked in way too early for sunset?
- mangeletti 11y agoI might be a majority shareholder of the following opinion, but I feel like it needs to be said. CSS was an art, and a science. Websites like csszengarden.com showed us the promise of style sheets, and the galleries of "CSS sites" during the mid to late 2000s demonstrated what amazing works could be taken from photoshop (and Fireworks!) and made into beautiful, pixel-perfect layouts. I always felt proud to make a website with only semantic HTML and CSS, and it always worked well. Even with all the browser issues (namely those of IE6), it was easy to write cross-browser compatible code that was clean and beautiful. The (C)ascading part of CSS was still considered a feature, and deeply understanding its implications was an acceptable challenge. Then came The Age of Great Coupling & Frameworks (made that name up) wherein CSS began to be regarded as a hindrance. Frameworks like Bootstrap became the status quo, because it meant you could go from 0% to 60% in half the time. But, no longer did anybody decide to go to 100%. The coupling I speak of isn't just a coupling of backend to frontend technologies, but a coupling of backend to frontend workflows. In a subconscious effort to become more efficient, we, as software engineers, began to find ways to incorporate automatic solutions for every problem (e.g., LESS). This is partly due to the very slow nature of completing and proliferating new CSS specifications, but in the long run all of these tools and frameworks have grown the barriers of entry, and have bifurcated the community in many ways (e.g., LESS vs SASS, responsive framework vs pure CSS, non-standard with polyfill vs standard, etc.). These differences are not the kinds of differences that cause anger (usually), but they make it hard to hire and train, and they make it hard for frontend engineers to work together easily. At the end of the day we're all building CSS and HTML with JavaScript, but if I strike up a conversation with 3 different frontend engineers, each will be as different as if I had chosen to talk to an astronaut, a vet tech, and a professional swimmer. That's almost no exaggeration. Diversity of skills and tasks within an occupation is a good thing, but at some extreme it decreases mobility. When I felt like I had learned CSS, well years ago, the thought never crossed my mind that someday choosing a CSS-related tool would be as much a career decision as choosing a primary programming language to focus on. FTR, I don't have solutions for the problems I pointed out, nor do I think we should somehow reset and go back to the past, but I feel strongly that we've made things more complicated than they need to be.
- acjohnson55 11y ago
- TeeWEE 11y agoDoesnt the shadow-dom solve the problems with css modularity. You just write the css for your component, and it doesnt leak into anything else... Why do you need something like css-modules?
- gravity13 11y agoThis is actually perfect for shadow dom, because it allows composition. You gotta remember, Shadow Dom is a double edged sword, - while it prevents styles from leaking in, it prevents styles from cascading too. And sometimes, cascading was a good thing. Without it, you need to reapply base styles, and that's annoying. With this approach, you can compose component styling by declaring what to inherit.
- tfb 11y agoI've been using JSS for everything. It makes the most sense to me. It's minimal in size and function to the point that any extra functionality can be quickly and easily added via `jss.use(plugin)`. And it's maximally modular. Every class is namespaced, and exporting everything to a single sheet for production builds is super simple, as it should be. https://github.com/jsstyles/jss https://github.com/jsstyles/jss