CSS Architecture for Modern Web Applications by Mike Riethmuller | CSSConf BP 2019

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
thank you although this Intex of CSS is relatively easy to learn and understand development teams around the world and especially large ones struggle to define and implement consistent maintainable and scalable CSS architecture now this isn't a new problem and in fact you probably know we have some fairly reliable and well tested solutions for these problems and you might even be surprised to learn that some of these solutions actually predates the SS itself but despite this unfortunately these solutions are often poorly applied or in the worst case they just simply disregarded in the context of modern JavaScript applications we're gonna discuss some of the reasons for this and what we can do about it and in the process of that we're going to take a look at some of the history of CSS architecture because I think that there'll be people in the audience today who don't have that context and sadly I think that the CSS community has done sometimes a pretty bad job at articulating this knowledge in ways that are relevant and accessible to new developers so let's try and do something about that today we're gonna start our story in 2009 yeah it was only ten years ago but it was a completely different time for front-end web development our chrome was virtually insignificant it had a market share of less than 1% the words responsive design didn't mean anything either support for media queries wasn't going to properly land until around 2010 and that would be the same year that even Marco would coin the words responsive web design in the now-famous a list a part article surprising to me when I did my research bootstrap was also yet to make its mark on the web it wasn't first published until early 2011 and for the most part the few open source UI libraries that we had available to us at the time seemed to emulate the desktop interfaces of the early 2000s now shadow out if anyone remembers the Yui library it has an age particularly well but in 2006 it was absolutely indispensable the weather this time was also exceptionally fragmented between late 2009 and early 2012 all of the major browsers were battling for market share we also had introduction of mobile browsers around this time as well and during that battle none of them really less than 10% of that market share the web was also maturing internet usage in developed countries had reached about 70% of the population which was nice if you were living in a developed country I guess 2009 was also the year that we got preprocessors so we got less and sass and that's the old version of sass not the newest CSS one so anyway all this stuff was happening and I can't be sure which if any of these factors had anything to do with it but it was around this time too that there was this explosion of ideas and thinking around CSS architecture so in 2009 Nicole Sullivan introduced the idea of oo CSS or object-oriented CSS and this taught us a lot the main idea was to separate the layout styles from the visual styles which he called skins and the other really important idea of Ojo CSS was to treat class names like these objects that we can extend and modify in different ways as you might have guessed and as the name suggests one of the key influences for this concept was object-oriented programming now I don't know how many of you have done any object-oriented programming but for those that haven't it's a way of writing programs with properties and functions that can sort of emulate or represent objects in the real world so I want to give you an example of this so I might have a user object in an application and it might have properties like a user name and it might have a flag which says whether that user is logged in or not it might have functions as well so if I want to login a use of the functions would like typically change one of the values here so my logged in function just changed the value of logged in to true I should probably check a password or something but I think you get the example now when we group these together in an object like this many languages call this a class and this is how you write one in JavaScript and an interesting thing about a class is when we have a class we can instantiate a new object so I could say user Mike equals a new user and then I can call the login method for that specific user and that user will be logged in in my application so that's it that's sort of object-oriented programming in a little over two slides you're all experts now but you're probably thinking like this is great but what in in the world does this have to do with HTML and CSS right they're completely different but perhaps they're not so different I could give you a different type of example so I could have a button object and it might have properties like type and value and it might have methods or functions like on click now this is also a representation of an object now admittedly it is a slightly different example than the one I gave you before we're not writing a class we're creating a new instance of that object by writing HTML but somewhere in the browser's own source code is a representation of a button object and went once the HTML is passed and understood by the browser it's going to make a call to create a new button with the properties that we set in the HTML something probably looks exactly like this so what should be apparent here is elements in HTML or more specifically the Dom have this object oriented model it's inherently present and we can't really step outside of it so it probably should influence some of how we look at style architecture on the web so let's take a look at some other sort of like fundamental features of object-oriented programming and how they relate more directly to CSS so in object-oriented programming another really important feature that I want to mention is that classes can be extended when you extend a class it's going to inherit properties from the parent object so in this example the button component is going to inherit some properties from reacted or component that's if you've written any react this is where it gets its life cycle methods and other things all of this sort of like happens a little bit magically so most object-oriented languages support this kind of inheritance and you probably know that when you get something that you don't want you override it it turns out that CSS also supports something similar to this kind of inheritance so in this example here we've got background purple and text tomato classes applied to the paragraph and we know that it's going to have properties from both of those classes so this is kind of almost a little bit like saying text tomato extends background purple it's going to inherit all of the properties from the parent class unless we explicitly overwrite them in CSS and you'll all know how to do that and because CSS is decorative it's actually often harder to work out which is the parent class in this example that can depend on the Cascade and the HTML and other things so we all know that this can get pretty complicated right and when there's a risk of inheriting something that you didn't intend and you're probably thinking I'll CSS you scamp this wouldn't happen in any other language except it does and one of the challenges with object-oriented programming is that changes to the parent object can cascade down and have unintended consequences on child items does that sound familiar to anyone so coincidentally also in 2009 computer scientist Joe Armstrong wrote in the book coders at work that the problem with object-oriented programming was you wanted a banana but what you got was a gorilla holding a banana and the entire jungle now there's many variations of this statement but what it means is when done badly classes in object-oriented programming and needlessly connected to all of these other things in the code you start having to override properties that you didn't intend to inherit and it starts to feel like you're carrying the legacy of the entire application any time you write something new once again that should be feeling familiar as it turns out there is also a well-established convention for avoiding this problem in object-oriented programming and you might have heard of the phrase composition over inheritance but what this means is that by combining these smaller independent and sometimes more abstract classes rather than just sort of in inheriting something and changing an existing object we end up with these smaller self-contained objects and this can help to reduce those unintended behaviors as a result of inheritance so in other words it's harder to turn something into something it's not than it is to build something new from a set of well considered and abstract building blocks that's how I like to think of it and that's how I like to think of CSS as well so object oriented CSS had this idea of abstract building blocks but I found that we're not really very good at considering what it is that makes an abstract building block in modern JavaScript applications and I want to ask the audience how reusable were the components in the last JavaScript application you've got to work on and I want to ask why is it so damn hard to make reusable components in JavaScript it really is so you might have seen this slide before the idea here is basically that we reject the separation of concern along these technology boundaries and instead that maybe components make a better separation of concerns and this idea resonated with a lot of people and I understand why I kind of agree with this and I've been co-locating a style sheets and JavaScript files for a long time but I feel like we've rushed to this without necessarily considering what is it about components that make them a good set or a good separation of concerns and when I think about that I think that good abstract building blocks for me the answer is not really as simple as the visual boundaries of a component you can't just draw a box around the design and be done with it and once again I feel like we have some answers to this problem in the history of CSS architecture so the meteor object was a classic example of this idea of an abstract building block and it was the probably the poster child of object-oriented CSS the idea is that you have like this title in this image and the image might be positioned to the left or the right and you might have a date or you might not it doesn't really matter the point is that the layout is separate from the content there's just these slots that the content gets rendered into and with these basic patterns and a few variations on this we can create a whole range of different types of content including user profiles comments it's the basic building block for sites like Twitter Facebook once you start looking for this on the web you'll see it absolutely everywhere and we can apply this concept to modern JavaScript applications too by thinking about the different types of responsibilities that UI components have so object oriented CSS gave us layouts and skins and I want to talk about some of some different types of components the first one I want to introduce you to is layout components now layout components are responsible for the positioning and spacing of themselves as well as the items inside them I have some tips for working with layout components so the first one is that layout components should own both sides of the parent-child relationship and what I mean by this is in modern CSS right in in layout in modern CSS there's usually a flex container and a flex item in a grid container and a grid item right there's these two things parent and child which together are responsible for layout and conflict arises when the Styles applied to these two things don't necessarily match and so when they're separate components that becomes very difficult so what you want to do is you want the layout components to own those concerns and there are a few different ways that we can do this so we can use the star selector to target all of the immediate children of a layout component this works even with CSS in jeaious libraries or at least all the ones that you should be using and you might be interested to know that the star selector doesn't increase specifically so if you need to actually override this with classic CSS that works as well this approach might seem a little bit simple but in most cases it just works and probably should be the first thing that you reach for in many situations another option is the layout component can be responsible for rendering the mark-up that wraps child items so this allows us to more directly own both sides of that parent-child relationship it also means that we can when we loop over something like a list we can ensure that those items have the right elements used and we can also ensure accessibility so this is a really great technique if you have a very structured thing and you want to insure specific accessible and semantic markup however this is a little bit problematic if we have like more items being passed down to that component we might have multiple slots that we want to render a things into they might be dynamic layouts and things like that so as a final escape hatch for more complicated components we can simply export these styles from the parent component from the layout component and then import these in child items where we want to use them so this allows you to co-locate those layout concerns but it also creates like a direct link or dependency between those two items which is always there but that actual link or that dependency in our code is usually absent and that's where a problem should have arise when we move things around and don't realize this dependency so that's that's my final tip for working with those in addition to layout components we also have these UI components which I've already sort of talked about and these are the things that get rendered inside of those layout slots now I have a few tips for working with those as well the first one is that UI components should be little more than decorated HTML elements and what I mean by this is you might have an input and a search button together like this I would call a structure like this layout but the button and the input individually are both UI components they might have styles like this that look absolutely ridiculous if they're not used together and they might always be used together but this this visual link is not the right reason to co-locate these Styles separately they make a far better set of reusable abstract building blocks my next tip is that UI components should be size agnostic and that means avoiding fixed widths and Heights wherever possible when UI components overflow the layout containers that means that something's probably not right with the layout and the solution is not to add CSS to the UI component to sort of fix that please please please please please fix this at the source because I've spent so much time on picking this in projects and the more patches we add the harder it becomes I know it's not always simple so if you need use utility classes utility components or props if you need to override specific components when you're working instead of like Java Script land here but whatever you do avoid hard coding fix widths and Heights wherever possible if nothing else other than visual consistency in the design it's important to know the number of variations that we have for UI component it sounds simple but it's actually incredibly hard to know when working with modern JavaScript applications and luckily again I feel like we have some solutions from CSS architecture that we can draw from in 2011 shortly after oCSS the wonderful Canadian gentleman Jonathan snook gave us max now Smacks taught us how to like categorize different parts of our stylesheet to deal with things like themes layouts global defaults but most importantly for my talk is application state jonathan reached many of the same conclusions as nicole did and i don't want to cover that ground again but unique to Smacks were these ideas of state in what he called modules I'm going to call them components so to paraphrase max we usually have or we can usually reduce the UI state down to three main types modifier states behavioral states and pseudo states typically you can only have one behavioral and one modifier state active at any time and smacks even had techniques for ensuring that we did this it suggested using data attributes so that selectors can only really target one item because the data attribute can only have one thing unlike a class the good thing is that like libraries like react and angular they actually make this even easier so when I when I'm trying to work this out right we should only have large say loading as a behavioral State and focus we should only have one of those columns active and when I start a project I like to map out the UI state for components like this if you find that it's possible to have two behavioral States active at any one time what you can do is you can split these into two categories say Network State and the red state if you can imagine for an article or something but be careful if you do this right because usually when I find this is the case I very quickly realized that I actually have two components here pretending to be one once I know how many components I have I can draw them like this because life's easier when that's not the case but this state is sometimes additive right behavioral states might change depending on the modifier state and the pseudo state might change depending on combination of the behavior and the modifier so if we think of these variations is kind of like one direction all right the behavior state becomes easy - sorry the total number of state becomes easy to work out it's just the total number of variations is that the number of state categories that you have times the number of possibilities for each so if we have three categories and three variations we can have 27 possible UI states for a component that's really important to know that it sounds like a lot right but obviously not every combination matters the disabled state might look the same for every single one of the modifiers and maybe the pseudo states are the same no matter what the the other state of the component is so you can just cross out items and you end up with a list like this now CSS actually forced us to flatten this state tree and to have usually a single selector that would represent every combination of state that we had available and although this was sometimes tedious this makes us acutely aware of how many different variations it has and assuming that the CSS is written well it's also fairly easy to see what styles were applied in any case you just sort of read the the selector that applies to the current state maybe you have to read to and add them in your head but that's not too bad now don't please don't read this but JavaScript doesn't force us to flatten the state tree in any way this concept of different categories of state is often completely lost and at worst and sadly on a lot of projects I've worked on the resolution of CSS properties comes down to business logic in the style function so you've probably all seen examples like that we can vastly improve this by giving a better resolution of props before we pass them to the style function and although this is an improvement and probably representative of the vast majority of large CSS and J's projects that I've worked on this is not ideal as this scales you need to consider how each individual property here affects each individual CSS property and if that is a complex set of logic that's really hard to work out you can't quickly know how many variations there are for a UI component and this makes Mike sad and that should be a goal to avoid on any project so furthermore if the props that we pass down to the style function don't represent a set of finite sort of state categories how do we know that the values that we resolving in that style function are valid and something that is intended by the design and this is not something that typescript is going to tell you right so being able to have these finite categories allows you to know that you're not going to end up with large and small active at the same time or loading an error if you can't read that thing if your stars aren't organ or make in that way that can be problematic I think David's going to touch more on state machines in in here or CSS state machines and his talk after me so I'm not going to go into much more detail there I do want to share a solution but it doesn't des matter matter to me whether you're sort of like composing these these states through class names template strings or objects in JavaScript what's important is that we have a single representation for each of the different UI States one of the challenges in modern JavaScript is that there's actually too many ways to try and do this I think that we need some better standardization around how we approach problems like this in CSS in jeaious because we kind of had that for CSS and then we've largely disregarded a lot of that knowledge and I'm not saying that this here should be the solution but I'm not saying that it shouldn't either so if you want to adopt this that's fine but what I like to do is I like to have a property that I passed to a style function a modifier and a behavior and I can only have one of those these values then get passed on to a function like this which will resolve the actual Styles so what's happening here is I've got some default Styles like font size and then I'm just kind of grabbed from an object here with the key that I passed a specific set of styles and I'm going to add those to this object that I'm building up in this function here and I'm gonna do the same for behaviors now what that means is we can quickly read sort of what's being added there's no resolution of state here so the real beauty in this approach is that using custom properties here we can set the modifier value so we can set the value in the modifier here that can then be used by the behavior so that gives you that branching capability that we had while keeping this this object flat and readable and I think like using modern features in CSS like this together with JavaScript applications can be really a useful pattern and that's the kind of thing that like probably most of us here should be bringing to our team so I want to encourage you to do that I absolutely love this pattern if you don't that's okay now you might notice some inspiration from the terms here from been things like modifiers and behaviors and it wouldn't be a CSS architecture talk really without mentioning Ben so the history of BEM is actually slightly harder to trace it started with the Russian tech company Yandex just a small company and it it might have been used internally before many of us particularly in the West became aware of it but I can say that it exploded in popularity around 2012 when people like Nicholas Gallagher and Harry Roberts started writing and talking about this so in 2012 Nicholas Gallagher wrote this article about HTML semantics and front-end architecture I encourage you to look it up I absolutely loved this article still nicolas doesn't mention CSS architecture once in the entire article but he mentions components and unbelievable 47 times in 2012 it's also in this article that Nicolas first talks about his experiences with Bam and what I think he realized that many don't is that many people think that Bam is just is like naming convention that that helps them to avoid specificity clashes in the terrifying global scope of CSS but the concepts of block element and modify are actually a really solid expression of different concerns relating to component architecture on the web so that should be really useful in modern JavaScript applications I think part of the reason for the success of BEM is that its strong and obvious naming conventions allowed developers to use this without necessarily understanding the reasons behind the principles and understanding everything behind the concept and that's okay so Ben gave semantic meaning to different parts of components and I think this is something that we sorely need in modern JavaScript applications they can be components can be so many things right but we don't have to make these distinctions and I've been like kind of drawing a few distinctions here which you may have picked up on and I think when we don't do this when we don't have these distinctions it leads to an unhealthy mix of different concerns within our UI components so to help us avoid this my final tip is consider naming some kind of naming conventions for your components I don't care what you use but it helps me to understand what your intentions are so for me what I do for you I components is I just call it by the component name and when I see this I immediately know that this is a UI component it should be just a visual element I know that it should have no width and height properties and it probably doesn't have many display properties either I should know that it can have state modifiers and I should know that it contains no business logic if I prefix a component with layout I should know immediately but again it has no visual styles I should know that it has state modifiers it might affect the layout of child but I know also that this component isn't going to contain business logic so I've talked about two types of components and I've said they both don't own business logic and this introduces you to the final type of component that I want to talk about today and that's a container component this is where the application logic lives so it resolves that modifier and behavior state before passing it off to to a style function or something a confection resolve data can set up callbacks events all of the things that applications need to do and this is what should wrap your layout and UI components you don't need to use the conventions that I'm mentioning here you don't need to prefix that with component or layout if you don't want you can group them in different folders you can add comments at the top of your source code if that's convenient for you whatever works for your team the important thing is to give semantic meaning to components just like BEM did for class names so that we can immediately transfer this knowledge of what our intentions are for this component as we build things together because that's what most projects are we're building things together and I think that's where a lot of the difficulty is and that's a lot of what CSS architecture was about so in summary it's the same problems that we've been trying to solve here the challenges that we face with style architecture in modern JavaScript applications component-based architecture are the same problems that we face with class names are the only difference is that the composition methods have changed so if you're a talented JavaScript developer and you're telling me that you know nothing about CSS then I'm sorry but you're not even trying and I know that's like a little bit mean but I'm gonna be mean to CSS people in a moment as well so so many of the architecture sorry many of the style architecture solutions applying knowledge and understanding from software architecture and and foundations in computer science right and I know many people who understand these complex problems but they fail to see similarities or worse yet they choose not to apply this knowledge to decorative front-end code and this disappoints me again should be a goal not to so my colleagues and friends who helped to establish some of these conventions in CSS architecture were skilled engineers with broad skills who applied knowledge different disciplines and I think that's what we should all be trying to do at the moment we're not the worlds apart that we pretend to be so I think the message here is to encourage us to start talking about these problems with with each of our understandings to the CSS people here in the audience we need to do better when we're engaging with these problems new tools like CSS nsj they can help us and they also bring about a whole bunch of new challenges and these are challenges that all of you people are really well positioned to understand and solve and we need to do better at articulating our experience and knowledge and ways that's relevant and accessible to to new developers or developers that come from from a different world to us and to that end I want to leave you with some practical suggestions for questions that you can ask on any project the first one is how many UI states can a component have this is a really important discussion point how can you easily validate which states are currently applied and that they're valid States intended by design how organ Amish are your stars this means how quickly can you read knowing that like the particular modifier or a particular behavior is currently active how quickly can you know and understand what CSS properties get applied in that case and if you can't do it in a few seconds then that's problematic are you creating sensible abstract building blocks or are you just drawing boxes around the design and building your components this way do they reflect a unit of visual design and if they do ask why are you separating the layout from the visual design where that is a sensible and appropriate are you separating application logic from UI components that's another big one even with how we pass props down even small bits of logic we've got to keep on top of those things and finally and probably the most important one how do we give semantic meaning how do we communicate our intentions and meanings to other developers on our team and I think that's really important and that's one that I'm gonna leave for all of us to discuss itself together thank you Budapest's I hope that you've left you with some practical tips or at least something to think about on your next project it was an absolute pleasure thank you so much Thanks
Info
Channel: JSConf
Views: 9,694
Rating: 4.8929768 out of 5
Keywords: architecture, css architecture
Id: ZWPMzJfJHnc
Channel Id: undefined
Length: 28min 52sec (1732 seconds)
Published: Wed Oct 30 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.