← Back to context

Comment by dt2m

4 years ago

Looks cool. I'm honestly curious as to why a lot of new web languages/frameworks are mixing logic and content in the same file again though. The distinction between HTML, JS and CSS always made perfect sense to me. Anyone care to enlighten me?

(Disclaimer not a web but backend dev.)

In my experience it's much more important to modularize/capsulate/segmentate by groupings of business logic then by groupings of implementation details.

Applying this to web applications (not simple text focused websites) this would mean that its preferable to have everything (HTML+JS+CSS) related to a specific widget (e.g. counter) in one place, instead of splitting it into many parts sprinkled across many files potentially in different folders. Similarly you also would e.g. want the CSS to be encapsulated as to the component as far as possible.

Its a bit of a different matter for classical html documents where the HTML made sense without JS or CSS and both where thinks you added "on top" to "just make it a bit nicer" but this isn't the think anymore for modern webapps (and many fancy websites).

Also if you work in a situation where you have many huge teams working on the same UI at the same time touching the same logical component (but normally different aspects of it) then having a more clear segregation can also make sense, but >99% of all companies are not ever in that situation.

This is also for example a major critic I have with react, it splits one logical unit across different files making it much harder to reason about it for the benefit of adding a bit more decoupling which isn't needed by >99% of dev teams.

  • Interesting, that makes sense. I'm thinking about a CLI analogy: you could write a program in C for the logic, some table specification markup language for the terminal layout, and a stylesheet for the colors and text styles. It would feel so cumbersome. The distinction between creating a document and a program is critical.

Personally I've always been kind of confused by the common best practice of separating everything. React and Vue single file components made so much sense to me.

I guess if I were to rationalize my position, I'd say it's because I have a hard time finding related things when they're separate. If a button or "a" tag have a special click handler, I want to know when looking at it. If it just has classes, then I don't know if that are for style or if they're for behavior. I know there are some conventions out there where you prefix classes with "js-" etc, but if you just use "onclick" then it's obvious and you don't need a convention.

  • Personally I think it's not so much about separation of concerns/technologies per se, it's that this debate boils down to a different debate under the hood: the one about folder-by-type vs folder-by-feature[0].

    The gist is that folder-by-feature is generally preferrable because it requires less context switching (in the literal sense of jumping between multiple different far away folders and scanning each for the thing you're looking for)

    Single file components force you to organize code in a folder-by-feature structure, to a large extent. You can use folder-by-feature structure alongside with separation of technologies, it's just not that common to see it because the tooling to support it is not quite as optimized.

    [0] https://softwareengineering.stackexchange.com/questions/3385...

    • > You can use folder-by-feature structure alongside with separation of technologies, it's just not that common to see it

      Angular is a pretty good example of this. The HTML, CSS, unit tests, and code are all in separate files, but they have the same base name and are grouped together in the same place.

  • It's fine if you have a few colors, but with 50+ lines of SASS/component I'd rather have them separately.

    > I have a hard time finding related things when they're separate.

    Store them in the same directory?

    I agree on the events/business logic that they make sense to couple with the template code.

    • With something like Svelte, I see no reason an editor couldn't let me choose if I want to see the JS/HTML/CSS in the single file (as it is on disk) or split it up into separate editor tabs for me.

> The distinction between HTML, JS and CSS always made perfect sense to me.

Really? HTML is already heavy on syntax, and the whole point of SGML-style angle-bracket markup is to invisibly structure text hierarchically and sneak in rendering properties or other "metadata" not rendered to the user, via attributes. In which universe, then, has it ever made sense to write

    <div style="color: red">

rather than

    <div color=red>

in a document representation language? Let alone today's CSS atrocities. Mind, I'm not talking about CSS' out-of-control layout model complexity, but inventing a new syntax (or a thousand microsyntaxes really) on top of already syntax-heavy markup.

If you think about it, CSS appears to have gotten these ninja super-powers because HTML was locked in a decade-long stagnation while W3C was busy with XML, RDF, and whatnot. Then again, in the last decade using <div>s for nearly everything was frowned upon, so with the precedent set in the decade before, CSS just had to re-order, re-place, re-arrange ad absurdum without any discernible mental discipline. Or, maybe the CSS WG people just couldn't stop.

The end effect is that CSS isn't approachable for even seasoned graphic artists let alone laymen; another effect being browser complexity resulting in monopolies.

A false separation-of-concerns narrative has ruined many languages and approaches (such as enterprise OOP); for the web it was particularly idiotic given it's founded on composable documents.

JS? Once it was out there, evolution of HTML and declarative UIs basically stalled because there wasn't anything you couldn't do using JS. Nevertheless, CSS had also grown into outlandish complexity. Basically, the "web stack" of today is what any standardization effort should've avoided.

  • > The end effect is that CSS isn't approachable for even seasoned graphic artists let alone laymen; another effect being browser complexity resulting in monopolies.

    This is so true. CSS has become a multi-headed Hydra whose parts appear completely unrelated to each other. I've been a developer and designer for more than 20 years and I have no idea what the parameter names and orders are for position, versus grids, versus float, etc. It's parameter soup. Who said the hardest part of programming is naming things? The CSS folks didn't get the memo.

    To do any real work with CSS means you have memorize a bunch of conflicting weirdness and/or keep a reference page open at all times. The idea of CSS frameworks to simplify or fix this doesn't work because, in order to write or debug what you create in those frameworks, you must know regular old CSS!

    It's turtles all the way down.

    • > To do any real work with CSS means you have memorize a bunch of conflicting weirdness and/or keep a reference page open at all times.

      I agree with CSS being complicated, but this statement is true for pretty much everything. Not a day goes by I don’t close 20+ reference tabs at the end of the day, not counting what I closed throughout the day. It’s simply impossible to be a polyglot and not use references.

      1 reply →

  • Not that I disagree that what we have today is a big mess but this sounds to me almost like the philosophy behind the old PHP version that everyone seems to hate. Personally I'd much rather have everything separated in a better HTML/CSS/JS than HTML+CSS+JS in one big pile. But I'm also not a fan of JavaScript at all, especially not of the hyped "one framework today, another tomorrow" that is JS development today. In my opinion in that area we are moving backwards very quickly.

    • Totally disagree as someone who grew up building websites as “cleanly” as possible, and now has spent many years doing all in one: the all in one is simply better in every way, it logically makes much more sense to group by component than by arbitrary style/structure/logic which just isn’t the right separation for many reasons that are written more fully in many places.

      I also made SnackUI to solve the last problems of fully inline styles: namely to make them work 100% between React Native and Web, to make them extract to atomic CSS on web automatically, to optimize even conditionals into CSS, and finally to make media queries and themes work the same between Native/Web. We’re launching a very large app with it here in not long, and I absolutely love how clear it is to work on.

      https://github.com/snackui/snackui

    • I think we're well past the period of a new framework every week - at least in a "real world" sense. Nearly all companies will settle on react or vue these days with a long tail choosing others, but this is no different than any other part of software development - lots of different databases, web frameworks, auth libraries etc all exist as well and are used.

      Most of these "new" frameworks are more because someone wanted to scratch an itch or solve a specific problem they had, and frontend code simply lends itself well to being open sourced. If you don't like the new js tools that are made, just ignore them.

  • Ok CSS sucks but what are the alternatives? What I see on other platforms requires some sort of WYSYWYG, which you can sort of do in the browser as well. They all generate XML, which I doubt is any more writable than CSS.

    What I’ll forever complain about (as a front end developer) is that there’s no distinction between a document and an app. You can start from a blog post and turn it into a rocket just by throwing more JS at it.

    I think only Google can fix it at this point:

    - come up with a better alternative for apps

    - reward websites that are content-only (or are guaranteed to support Reader view)

    Now you could start to have simple documents and a powerful app platform.

    Unfortunately this is hard to do as most developers will call bloody murder. So let’s enjoy CSS for the next hundred years, shall we?

It's because of components.

Web app dev has started focusing on single, separate, reusable components instead of trying to design everything on the page at once.

Often, in these components, the HTML, CSS, and JS is still separated, but now (theoretically) you can plug that component in anywhere (even a different app) and, as long as you feed it the right data, it should just work.

  • > It's because of components.

    Replying to you because this is the shortest expression of this sentiment, expressed in many different comments:

    No, it's not because of components. It's because of emulation of components by means of precompilation or JS execution. First-class components are available already, there's no reason to continue to emulate them, unless you need backward compatibility, or have another goal other than separating components.

    It's also not about "components" in the meaning of "widgets" - reusable bits of content+view+behavior - because these can be trivially made with standard HTML + CSS + jQuery plugin. It was done since before the DHTML was a thing (hello <iframe>!).

    Instead, it's all about web apps, how they achieve responsiveness, and the fact that the more the framework knows about the content (including how it should look in all its states), the easier it is to optimize it consistently. I get that, it's ok for web apps, and it gets better the more nice syntax you throw at the problem (up to a point, as usual), because once you have enough of syntax extensions to replicate the important features of HTML and CSS, you can go absolutely nuts on the actually generated code and nobody would care.

    On the other hand, using web app frameworks to write web pages is bad - do you really need to optimize for responsiveness if almost everything you see on the page has exactly one (or two, with hover) state? The same is probably true for languages designed for web apps: using them to write web pages can be tedious and more trouble than it's worth.

    TLDR: it's because ~components~ web apps.

The pragmatic answer is that, for the the large companies usually behind those frameworks, they can have many independent teams that are working on split components, without marching on each other's toes.

But to me, there's a parallel to be made between both the newer trends of components and micro-services, and the old idea of Object Oriented Programming. In all cases, you get sold on the idea that everything should be cut down into tiny pieces.

Theoretically the separation of concerns has tons of merits, but in practice there are a lot of rough edges when those separate pieces have to interact with each others.

And the tradeoffs may not always be worth it when your project isn't on the scale of those large companies (it very rarely is).

  • I agree. The real difficulty in software engineering is at the seams where systems or components have to interact with other systems/components. The more seams, the more difficulty.

    The key though is that componentization is useful when you find yourself writing the same code over and over again. That's where DRY steps in and says yeah this should be its own component.

    This is one reason monoliths are great as an app structure, because they let you be as DRY as possible and have as few seams as possible (making a component within a monolith doesn't create an external dependency, no seam). Additionally, there are options nowadays (ruby on jets for example) that let you have a monolith repo structure but each controller endpoint gets deployed as a separate lambda. So you get to have your cake and eat it too.

    The analogy really does work fairly well at every level of software engineering, from frontend components to backend services.

    • Yep, the way I see it is, how much abstraction are you willing to accept.

      Intuitively you may not want too much, until you find out that maybe you could have needed a bit more because of the repetitiveness. So frameworks that give you the option to gradually increase it when you need are the best. And when the documentation follows those patterns it's really great (I'd put Vue in that category).

      Usually the thinking was, while it may not make sense, it will someday when my project grows, so let's adopt it right away. And for years I would have said that was a decent advice. Nowadays I think that with some of the more extreme scales behind some of those trends though, it's not always as clear cut.

Separation only works for so-called leaf components: buttons, links, tabs etc. that can actually be reused.

And even then you will definitely run into issues such as "in this particular case this particular tab will look like this".

While the web was mostly leaf components (text, articles, images, links) this separation kinda worked. The moment you move into app territory, there are not that many things that are reusable and benefit from separation, because your UI is directly dependent on business logic and vice versa. And because every screen in your app is a unique view into a unique part of your functionality.

  • Very true. Even in "leaf" components (I'd never heard them called that. Cool.), the actual appearance is often dependent on some state that only the parent knows. Is the button highlighted or dimmed? Blue or red? Well, the button component doesn't know. (It shouldn't). But the parent who spawned it must know and pass that information into the button by a param.

    This should, ideally, be as short and sweet as possible. In reality, like you say, the two ideas (visual + biz logic) will always be married in any non-trival application.

    • leaf components as a term appears in various discussions on web components. Many people don't see the value in full-blown web components(as they have lots and lots of unsolved issues), but agree that they may fill the niche/need for "dumb" reusable components at the end of the DOM tree (hence, leaf :) ): date pickers, buttons, links, all that kind of stuff.

      1 reply →

I think eventually everyone just realized that so much of the styling is dependent on the element hierarchy that makes up the page that it’s pointless (and indeed painful) to separate your HTML from the component that uses it.

If you are actually using components, that isn’t much of an issue.

In a time when you’d be returning a whole document every single time, it might make sense to say ‘style this one document with this one stylesheet’, and even more so in a time when HTMl was still more or less semantic (e.g. an actual document).

  • This! Usually CSS doesn't even make sense outside the context of the page/component it's styling.

    There's also some nice stuff with modern tooling, where CSS is global by nature but writing it with your JS allows for the platform to automatically namespace your CSS, making styling behavior much more consistent.

    Separately it also often makes sense to style things not just based on the HTML produced but also based on data stored in JS; writing your CSS with your components allows for a greater level of dynamic styles (which, to be fair, if you can achieve with pure static CSS is preferable, but it's not always the case).

> ... [W]hy [are] a lot of new web languages/frameworks are mixing logic and content in the same file again...?

In olden days, the DOM was treated like something shared. This could lead to a single DOM elements receiving changes from all over the place: Multiple CSS selectors would include it and apply style rules, and multiple JavaScript scripts might select and manipulate it. Spitting the CSS/HTML/JavaScript into multiple files just makes it harder to know what's doing what.

The new frameworks are built around the idea that when we need to manipulate or style a DOM element then it should be isolated from the rest of the DOM, and so should the CSS and JavaScript that do the manipulating. In other words, what we often call "components".

For convenience, we often group these three things into the same file, or into small files sharing the same directory.

Reasoning about them much simpler, because each one is like a tiny HTML document with just a few DOM elements. No need to review hundreds of CSS selectors or JavaScript event handlers, because everything is together in one small package.

  • If you isolate the DOM elements from each other, then how do they share common styles? You certainly do not want to define the font type for each DOM element individually, do you?

    • Lit (which evolved out of Google's Polymer project) has many of the same goals of the Imba project and tries to reduce the spaghetti of something like AngularJS.

      It handles CSS by letting you define it in within an individual component (file) but also import a style from another file. That way, your shared styles are in one place and only the overrides or extra styles needed for a special component are in its file.

      I think it's wonderful!

      Not to denigrate this project in any way, but most or all of its goals are already met by Lit[0]. Instead of a new language, it uses regular TS and regular CSS.

      [0] http://lit.dev

    • The development is isolated, but the components are still placed somewhere in the dom, so regular hierarchy/specificity rules apply.

      Granted, some UI frameworks do add a lot of redundant code to maximise component independence, then offer JS-based or class-based theming to keep development DRY.

A feature usually consists of all three HTML/CSS/JS.

So, if you split by technology, you don't have the code belonging to one feature in one place.

  • This is the most correct answer. It also felt wrong to me when I first started doing serious frontend development (I started it with AngularJS), but than it all made so much sense after a few projects and after I _experienced_ the benefites.

For web apps, you often want your content/HTML to dynamically render different elements depending on application state. Using a separate template file and having your logic plug into the template is often more complicated than just having your flow logic (if/else chains checking application state) return bits of relevant HTML/content inline.

Hard to describe, but it feels like it makes much, much more sense. I think it's because the divide between html/css/js is supposed to be one of concerns, but in reality the concerns are interwoven in many ways, and leads to issues when using them at scale. None of the scaling issues I've faced in the past re-occurred when I used a framework that combined the languages into single files.

A bad metaphor I just came up with: You're cutting a birthday cake. If you do the horizontal cuts you could at best have like 4 cuts and it's very hard. If you do the vertical cuts you could easily have like 16 cuts for everyone.

Because the horizontal way separates the concern the wrong way, or more precisely, the non-scalable way.

The idea is the same way that backend architectures are migrating from layered architectures to microservice or DDD alike architectures.

HTML, CSS, JavaScript separation of concern: 3 layers. Layered architectures: presentation, application, domain, infrastructure etc. There's only O(1) number of layers, so it's not scalable enough for modern applications. You can came up with more layers, but it's still O(1) and would be more strechy, despite the business and codespace are growing fast. People will struggle because everytime they change one layer, they have to find the corresponding other layers of code - it starts to defeat the purpose of separation where it should help people not caring other layers when modifying code.

A more critical separation of concern is to have O(n) separation: you can different domains like products, inventory, sellers, account managment, custommer support etc. If your business continue to grow, you could have more of them. And more importantly, it's much easier to separate teams into pizza-sized teams than layered separation.

Don't get me wrong, layered architectures are still useful. In fact, most of the DDD implementations are layered. But there's mental overhead when you introduce separation. Communities like React and Vue decide that it makes sense to merge layers in Front-end for local reasoning over separation, and accoding to my experience it works well (because I find it's very common to modify HTML, JavaScript, and CSS at the same time before I even started to use React).

The distinction makes sense on documents but it starts to break on apps. Javascript depends on HTML and HTML is generated by JS.

  • Your concept is right but that wording isn't quite right. JS runs fine without HTML and thousands of lines in any web app don't even touch HTML. Node is HTML-free, for example. Also, of course, HTML, can be generated in a thousand ways and has no dependencies on JS.

    I think what you were going for is the idea that, beyond a trivial application, the visual appearance stuff is always going to be tied to some app logic or business logic or state or whatever word we want to use.

    And that's very true regardless of what framework or language we choose.

    • You read that out of context. We’re talking about apps, web apps, SPAs, and specifically situations that bring you to mix HTML and CSS into a JavaScript module.

      That situation most likely requires HTML (DOM) generation in the browser, which can only happen in JavaScript.

      So, I reiterate, the HTML is generated by JS in these interactive modules.

      You could generate the HTML on the server and then use jQuery to toggle elements… or just create full-JS components that take care of everything, giving some input data, instead of separating the HTML from the JS.

As others have mentioned, it's being used when writing components. Why does it work so well for components though, since you could just as well still separate the CSS? I think it's because of code co-location. Everything that describes how a component looks and functions lives in one file only. That's also why inline styles and utility libraries are palatable now, it's easier to reason about if it's described directly on the element, and you don't need to remember to update all usages of the inline style since it's a re-used component. It's even one step less indirection than using class names in that context, which is handy.

I also think most people are quite bad at organizing CSS, so I'm personally thankful for this change even though I love a well organized simple CSS/HTML site. It means less projects I inherit are rabbit warrens of legacy CSS to unravel.

> The distinction between HTML, JS and CSS

When all three of these things have to care very directly about eachother, separating them makes less sense.

It never made a lot of sense in practice. Designers couldn't maintain CSS files because the language was too complicated for most. And these days, most DOMs in dynamic web pages are generated by the JS so the HTML/JS separation doesn't make sense either. Separating content, presentation, and logic is a good idea in theory, in practice not so much.

This is exactly why I prefer Angular to React.

Our designer wouldn't have been able to deal with HTML markup within the JS files in React. Having the HTML and (S)CSS separated out made life much easier for him in Angular.

(edit: Naturally downvoted due to being slightly critical of React on HN. Which happens every time.)

  • I'm not sure you are being critical of React. There is nothing about React that prevents you from separating the HTML and CSS into separate files.

    You are being critical of separation choices. To which I am curious why embedding the CSS and HTML inside a Javascript file makes any difference to the designer? In practice, we often see slightly different syntax to accommodate, but I cannot imagine that is a true barrier. The CSS and HTML (or their slightly modified equivalents) are still logically separated from the rest of the logic in the file.

    • I build all the components and get them working with mostly 'vanilla' styling. Then he brands/styles any he needs to by simply editing the .html and .scss files.

      He has no idea about how the TypeScript/JavaScript files work. He doesn't really have to touch them, unless to maybe see what extra data the component model contains if he wanted to dig deeper and display other things.

      1 reply →

Another way too look at it: Do you prefer backend, frontend, and databases to be separate teams, or should each team have ownership over their own backend, frontend, and db?